// 工具类型
type UnpackedFn<T> = T extends (...ags: any[]) => (infer R) ? R : T;
type Fn2 = UnpackedFn<typeof foo>;

type fn = (x: boolean) => number;
type Fn3 = UnpackedFn<fn>;




type User = {
	a: (x: string) => void;
	b: (x: number) => void;
};                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
// 工具类型
// 注意：这里是逆变位置应该参数R存多个值 取交叉类型运算
type PropertyType<T> = T extends {a: (x: infer R) => void; b: (x: infer R) => void} ? R: T;
type Pro1 = PropertyType<User>; // string & number ⇒ nerver

type User2 = {
	a: string;
	b: number;
};
// 工具类型
// 注意：这里是协变位置应该参数R存多个值 取联合类型运算
type PropertyType2<T> = T extends {a: infer R; b: infer R} ? R: T;
type Pro2 = PropertyType2<User2>; // string | number






type union = { a: 'a'} | {b: 'b'};
// 工具类型
type UnionToIntersection<T> = (T extends any ? (ags: T)=> void : never) extends (ags: infer R) => void ? R : never;

type Intersection = UnionToIntersection<union>;// {a: 'a'} & {b: 'b'}





// 工具类型
type UnPacked<T> = T extends (infer U)[] ? U : T extends (...ags: any[]) => infer R ? R : T extends Promise<infer U> ? U : T;
// 使用
type T0 = UnPacked<string>; // string
type T1 = UnPacked<string[]>; // string
type T3 = UnPacked<() => Number>; // Number
type T4 = UnPacked<Promise<string>>; // string
type T5 = UnPacked<UnPacked<Promise<string>>>; // string



// infer的新特性：infer在推断元组类型使用中可以简写

// 不简写
type FirstString<T> = T extends [infer R, ...unknown[]] ? R extends string ? R : never : never;

// 简写
type FirstStringE<T> = T extends [infer R extends string, ...unknown[]] ? R : never;

type A = FirstString<[string, number, boolean]>; // string
type B = FirstString<['hello', number, boolean]>; // 'hello'
type C = FirstString<['hello' | 'word', number, boolean]>; // 'hello' | 'word'
type H = FirstString<[number, boolean]>; // never